using System;

public class RC4
{
	private byte[] m_sRC4;
	private byte[] m_pKey;
	private uint m_nKeyLength;
	private uint m_iRC4;
	private uint m_jRC4;
	// RC4 default Key
	static public string RC4_KEY = "Little-Worlds Studio - 69";	
	
	public RC4()
	{
		m_sRC4 = new byte[256];
		m_iRC4 = 0;
		m_jRC4 = 0;
		SetKey( RC4_KEY );
	}
	
	private byte[] StringToByteArray( string str )
	{
		System.Text.UTF8Encoding encoder = new System.Text.UTF8Encoding();
		return encoder.GetBytes( str );
	}
	
	private string ByteArrayToString( byte[] byteArray, System.Text.Encoding encoder )
	{
		return encoder.GetString( byteArray );
	}
	
	
	public void SetKey( string sKey )
	{
		byte[] key = StringToByteArray( sKey );
		m_pKey = key;
		m_nKeyLength = (uint)key.Length;
	}
	
	public string EncryptToString( string sText )
	{
		return EncryptToString( StringToByteArray( sText ) );
	}
	
	public string EncryptToString( byte[] byteArray )
	{
		byte[] res = Encrypt( byteArray );
		
		System.Text.Encoding encoder = GetFileEncoding( res );
		
		return ByteArrayToString( res, encoder );
	}
	
	public byte[] Encrypt( string sText )
	{
		return Encrypt( StringToByteArray( sText ) );
	}
	
	public byte[] Encrypt( byte[] pSrc )
	{
		if( pSrc == null || m_pKey == null )
			return null;
		
		uint nSize = (uint)pSrc.Length;
		
		byte[] pDst = new byte[nSize];
		
		// Create the keystream
		InputKey( m_pKey, m_nKeyLength );
		
		// Encrypt
		for( uint x = 0; x < nSize; x++ )
			pDst[x] = (byte)( pSrc[x] ^ OutputKey() );
		
		return pDst;
	}
	
	private void InputKey( byte[] sKey, uint nKeyLen )
	{
		for( m_iRC4 = 0; m_iRC4 < 256; m_iRC4++ )
			m_sRC4[m_iRC4] = (byte)m_iRC4;
		
		for( m_iRC4 = 0, m_jRC4 = 0; m_iRC4 < 256; m_iRC4++ )
		{
			m_jRC4 = ( m_jRC4 + sKey[m_iRC4 % nKeyLen] + m_sRC4[m_iRC4] ) % 256;
			Swap( m_sRC4, m_iRC4, m_jRC4 );
		}
	}
	
	private byte OutputKey()
	{
		m_iRC4 = ( m_iRC4 + 1 ) % 256;
		m_jRC4 = ( m_jRC4 + m_sRC4[m_iRC4] ) % 256;
		
		Swap( m_sRC4, m_iRC4, m_jRC4 );
		
		return m_sRC4[( m_sRC4[m_iRC4] + m_sRC4[m_jRC4] ) % 256];
	}
	
	private void Swap( byte[] s, uint i, uint j )
	{
		s[i] ^= s[j];
		s[j] ^= s[i];
		s[i] ^= s[j];
	}
	
	System.Text.Encoding GetFileEncoding(byte[] byteArray)
    {
      // *** Use Default of Encoding.Default (Ansi CodePage)
      System.Text.Encoding enc = System.Text.Encoding.Default;
		
	  if(byteArray == null || byteArray.Length < 5)
		return enc;
		
      if (byteArray[0] == 0xef && byteArray[1] == 0xbb && byteArray[2] == 0xbf)
        enc = System.Text.Encoding.UTF8;
      else if (byteArray[0] == 0xfe && byteArray[1] == 0xff)
        enc = System.Text.Encoding.Unicode;
      else if (byteArray[0] == 0 && byteArray[1] == 0 && byteArray[2] == 0xfe && byteArray[3] == 0xff)
        enc = System.Text.Encoding.UTF32;
      else if (byteArray[0] == 0x2b && byteArray[1] == 0x2f && byteArray[2] == 0x76)
        enc = System.Text.Encoding.UTF7;
      else if (byteArray[0] == 0xFE && byteArray[1] == 0xFF)      
        // 1201 unicodeFFFE Unicode (Big-Endian)
        enc = System.Text.Encoding.GetEncoding(1201);      
      else if (byteArray[0] == 0xFF && byteArray[1] == 0xFE)      
        // 1200 utf-16 Unicode
        enc = System.Text.Encoding.GetEncoding(1200);


      return enc;
    }
}
